home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
video
/
pictetri.src
/
pictetri
/
pictetris-src
/
screen.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-10
|
18KB
|
498 lines
/***************************************************************************\
|* *|
|* screen.c: A version of Tetris to run on Linux SVGAlib console. *|
|* This module handles all the operations concerning *|
|* the Jlib bits. *|
|* *|
|* Authors: Mike Taylor (mirk@uk.ac.warwick.cs) & *|
|* Arturo Espinosa (arturo@nuclecu.unam.mx) *|
|* Started: Fri May 26 12:26:05 BST 1989 (tetris for terminals) *|
|* Dic 1, 1995 (pictetris) *|
|* *|
\***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <jlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include "screen.h"
#include "pictetris.h"
#include "utils.h"
#include "game.h"
#include "pieces.h"
image *pic; /* This is a struct of Jlib (palette,data) */
sprite_system *blocks; /* Another struct... sprite data. */
sprite_system *next_blocks;
buffer_rec *offscreen; /* The Jlib screen buffer */
static FILE *piclist; /* The pictures list file handle */
extern int rand_lines; /* Number of garbage lines will appear */
extern int black_bg; /* These are some flags which determine the */
extern int next_box; /* presentation of the screen */
extern int piece_no_next; /* Some parameters which I need for the */
extern int orient_next; /* next-piece box. */
/***************************************************************************\
|* *|
|* myrefresh() calls the jlib function screen_blit_fs_buffer() which *|
|* copies the buffer into the screen. *|
|* *|
\***************************************************************************/
void myrefresh ()
{
screen_blit_fs_buffer(offscreen);
}
/***************************************************************************\
|* *|
|* hoopy_refresh re-draws the screen while playing. *|
|* *|
\***************************************************************************/
void hoopy_refresh ()
{
setup_screen ();
draw_board ();
update_scores ();
myrefresh ();
}
/***************************************************************************\
|* *|
|* draw_border draws a three dimensional border in the corners *|
|* x1,y1 - x2,y2. *|
|* *|
\***************************************************************************/
void draw_border(int x1,int y1,int x2,int y2)
{
buff_draw_box(offscreen,x1,y1,x2,y2,1);
buff_draw_box(offscreen,x1+1,y1+1,x2-1,y2-1,24);
buff_draw_box(offscreen,x1+2,y1+2,x2-2,y2-2,17);
buff_draw_box(offscreen,x1+3,y1+3,x2-3,y2-3,19);
}
/***************************************************************************\
|* *|
|* The function print_msg() prints a short message centered on the *|
|* floor of the playing area, with a space before and after it. *|
|* *|
\***************************************************************************/
void print_msg (line)
char *line;
{
int i;
draw_border(152-COL(strlen(line))/2,183-COL(1),
168+COL(strlen(line))/2,199);
buff_draw_rect(offscreen,156-COL(strlen(line))/2,187-COL(1),
164+COL(strlen(line))/2,196,0);
buff_draw_string(offscreen,line,160-COL(strlen(line))/2,189-COL(1),1);
myrefresh ();
}
/***************************************************************************\
|* *|
|* The function clear_area() just puts the pcx on the screen buffer and, *|
|* therefore, erases anything there could be on it. *|
|* *|
\***************************************************************************/
void clear_area ()
{
buff_blit_img_to(offscreen,0,0,pic,0,0,IMG_WIDTH(pic),IMG_HEIGHT(pic));
}
/***************************************************************************\
|* *|
|* draw_area puts the pcx on the screen, then draws the borders for *|
|* the play ground, the scores box and the next_piece box if *|
|* necessary. It also fills the playing area with black if the option *|
|* is on. *|
|* *|
\***************************************************************************/
void draw_area() {
int i;
buff_blit_img_to(offscreen,0,0,pic,0,0,IMG_WIDTH(pic),IMG_HEIGHT(pic));
draw_border(111,5,208,192);
if (black_bg) buff_draw_rect(offscreen,115,9,204,189,0);
if (next_box) {
draw_border(60,5,110,55);
draw_next_piece_box(piece_no_next,orient_next);
}
draw_border(209,5,209+COL(20),9+LINE(5));
}
/***************************************************************************\
|* *|
|* draw_next_piece_box draws the nex... its quite self explanatory. *|
|* *|
\***************************************************************************/
void draw_next_piece_box(piece_no, orient)
int piece_no;
int orient;
{
int i;
int add=1; /* this is because most pieces have a (x,-1) upper */
/* coordinate... */
int next_block_no;
if (black_bg) {
buff_draw_rect(offscreen,64,9,106,52,0); /* draw black bkground */
} else {
for (i=0;i<16;i++)
buff_rest_sprite(next_blocks,i,offscreen);/* or the image that gets */
} /* behind the blocks. */
if ((piece_no==1)&&(orient%2==0)) add=0; /* except the vertical bar */
/* (piece_no 1,orientation 0||2 */
for (i = 0; i < NO_SQUARES; i++) {
next_block_no=(pieces[piece_no].index[orient][i][0]+add)*4+
pieces[piece_no].index[orient][i][1]+1;
/* calculate the number of the sprite */
/* (note the use of add to lower the figure) */
sprite_set_an_frame(next_blocks,next_block_no,piece_no+1);
/* set the color of the sprite according to the piece */
buff_save_sprite(next_blocks,next_block_no,offscreen);
/* this saves the piece of pic under the sprite */
buff_draw_sprite(next_blocks,next_block_no,offscreen);
/* finally draw the sprite on the buffer */
}
}
/***************************************************************************\
|* *|
|* check_pic_change calls setup_screen when total_time changes by 2500. *|
|* *|
\***************************************************************************/
void check_pic_change()
{
int picture_change;
static int picture_change_last=-1;
picture_change=game_level+rand_lines+(50000-total_time)/2500;
if (picture_change>picture_change_last) {
picture_change_last=picture_change;
} else picture_change++;
}
/***************************************************************************\
|* *|
|* setup_screen calls load_next_pcx *|
|* and saves the picture under the sprites. Then redraws the buffer. *|
|* *|
\***************************************************************************/
void setup_screen ()
{
int i,b;
load_next_pcx();
clear_area();
if (black_bg) buff_draw_rect(offscreen,115,9,204,188,0);
for (i=0;i<200;i++)
buff_save_sprite(blocks,i,offscreen);
if (next_box) for (i=0;i<16;i++)
buff_save_sprite(next_blocks,i,offscreen);
draw_area();
draw_board();
}
/***************************************************************************\
|* *|
|* load_next_pcx loads a new picture from the list file *|
|* *|
\***************************************************************************/
void load_next_pcx() {
char picname[256];
while (fgets(picname,255,piclist)==NULL) {
fseek(piclist,0,SEEK_SET);
}
picname[strlen(picname)-1]=0;
image_free(pic);
pic=image_load_pcx(picname);
if (pic==NULL) die (LE_USAGE,form("Couldn't load PCX from pictures list file: %s",picname));
screen_block_set_pal(IMG_PALETTE(pic));
}
/***************************************************************************\
|* *|
|* The function setup_curses should be called exactly once, near the *|
|* beginning of execution. It initialises Jlib, and notes that *|
|* this has been done, by setting the global variable in_curses. *|
|* *|
\***************************************************************************/
void setup_curses ()
{
int i;
int b;
offscreen=buff_init(SCREEN_WIDTH,SCREEN_HEIGHT);
if (offscreen==NULL) die(0,"Offscreen buffer could not be allocated.");
screen_set_video_mode();
kb_init();
piclist=fopen(PICLIST_FILE,"r");
if (piclist==NULL)
die(0,form("The file %s could not be opened.",PICLIST_FILE));
blocks=sprite_init(200,8);
sprite_load(SPRITE_FILE,blocks);
for(i=0;i<20;i++)
for(b=0;b<10;b++) {
sprite_set_xy(blocks,i*10+b,115+b*9+SPR_MAX_X,9+i*9+SPR_MAX_Y);
sprite_turn_on(blocks,i*10+b);
sprite_set_an_frame(blocks,i*10+b,4);
}
if (next_box) {
next_blocks=sprite_init(16,8);
sprite_load(SPRITE_FILE,next_blocks);
for(i=0;i<4;i++)
for(b=0;b<4;b++) {
sprite_set_xy(next_blocks,i*4+b,68+b*9+SPR_MAX_X,13+i*9+SPR_MAX_Y);
sprite_turn_on(next_blocks,i*4+b);
sprite_set_an_frame(next_blocks,i*4+b,4);
}
}
buff_clear(offscreen);
in_curses = 1;
}
/***************************************************************************\
|* *|
|* The function draw_title loads title.pcx and draws a little message *|
|* with the credits. *|
|* *|
\***************************************************************************/
void draw_title() {
pic=image_load_pcx(form("%s/title.pcx",TITLE_PATH));
if (pic==NULL) die (LE_USAGE,form("Couldn't load %s/title.pcx",TITLE_PATH));
screen_block_set_pal(IMG_PALETTE(pic));
clear_area();
draw_border(116,168,204,199);
buff_draw_rect(offscreen,120,172,200,196,0);
buff_draw_string(offscreen,"by Arturo Espinosa",124,176,1);
buff_draw_string(offscreen,"& Mike Taylor.",132,184,1);
}
/***************************************************************************\
|* *|
|* draw_options takes the variables that modify the game difficulty and *|
|* draws a square with the information and options available. *|
|* *|
\***************************************************************************/
void draw_options(int bg, int nb, int s, int rl, int tt, int gl) {
char yn[2][4]= {"No ","Yes"};
clear_area();
draw_border(106,120,214,199);
buff_draw_rect(offscreen,110,124,210,196,0);
buff_draw_string(offscreen,form("Black BG: %s",yn[bg]),114,128,23);
buff_draw_string(offscreen,form("Sound: %s",yn[s]),114,128+LINE(1),24);
buff_draw_string(offscreen,form("Next-piece box: %s",yn[nb]),114,128+LINE(2),17);
buff_draw_string(offscreen,form("Random lines: %d",rl),114,128+LINE(3),25);
buff_draw_string(offscreen,form("Level's speed: %d",tt),114,128+LINE(4),18);
buff_draw_string(offscreen,form("Free falling pieces:%d",gl),114,128+LINE(5),19);
buff_draw_string(offscreen,"Continue Keep config",114,128+LINE(6),26);
buff_draw_string(offscreen,"Quit View scores",114,128+LINE(7),27);
buff_draw_string(offscreen,"B",114,128,14);
buff_draw_string(offscreen,"S",114,128+LINE(1),14);
buff_draw_string(offscreen,"N",114,128+LINE(2),14);
buff_draw_string(offscreen,"R",114,128+LINE(3),14);
buff_draw_string(offscreen,"L",114,128+LINE(4),14);
buff_draw_string(offscreen,"F",114,128+LINE(5),14);
buff_draw_string(offscreen,"C K",114,128+LINE(6),14);
buff_draw_string(offscreen,"Q V",114,128+LINE(7),14);
myrefresh();
}
/***************************************************************************\
|* *|
|* The function update_scores() puts the sepecified values of score, *|
|* no_pieces and no_levels on the screen buffer. *|
|* *|
\***************************************************************************/
void update_scores ()
{
buff_draw_rect(offscreen,213,9,285,46,0);
buff_draw_string(offscreen,form("Challenge: %d", game_level+rand_lines+(50000-total_time)/2500),218, 12,1);
buff_draw_string(offscreen,"Score:",218,12+LINE(1),1);
buff_draw_string(offscreen,"Pieces:",218,12+LINE(2),1);
buff_draw_string(offscreen,"Levels:",218,12+LINE(3),1);
buff_draw_string(offscreen,form ("%d", score),218+COL(7),12+LINE(1),1);
buff_draw_string(offscreen,form ("%d", no_pieces),218+COL(8),12+LINE(2),1);
buff_draw_string(offscreen,form ("%d", no_levels),218+COL(8),12+LINE(3),1);
}
/***************************************************************************\
|* *|
|* The function draw_board() puts the current state of the global array *|
|* board[] ontop the buffer (each sprite is a cell on the matrix). *|
|* *|
\***************************************************************************/
void draw_board ()
{
int i, j;
for (i = 0; i < 20; i++)
for (j = 0; j < 10; j++) {
if (board[i+4][j] == PI_EMPTY) {
buff_rest_sprite(blocks,i*10+j,offscreen);
}
sprite_set_an_frame(blocks,i*10+j,board[i+4][j]+1);
buff_draw_sprite(blocks,i*10+j,offscreen);
}
}
/***************************************************************************\
|* *|
|* The function draw_piece draws or erases one of the tetris pieces on *|
|* the screen in a specified orientation and position. The form of the *|
|* function is: *|
|* *|
|* draw_piece (piece_no, orientation, y, x, flag) *|
|* *|
|* All the arrguments are integers. Flag is either PD_DRAW or *|
|* PD_ERASE, specifying the effect of the function. Piece_no is *|
|* between 0 and 6 inclusive, and specifies what sort of piece is *|
|* required. Orientation is between 0 and 3 inclusive, and states *|
|* which way up the piece is to be drawn, and y and x express the *|
|* position as an index into the 20 by 10 array *|
|* that is the board. *|
|* *|
\***************************************************************************/
void draw_piece (piece_no, orient, y, x, flag)
int piece_no;
int orient;
int y;
int x;
int flag;
{
int i;
int block_no;
for (i = 0; i < NO_SQUARES; i++) {
if (y+pieces[piece_no].index[orient][i][0] >= 0) {
block_no=(y+pieces[piece_no].index[orient][i][0])*10+
x+pieces[piece_no].index[orient][i][1];
if (flag == PD_ERASE) {
buff_rest_sprite(blocks,block_no,offscreen);
} else {
sprite_set_an_frame(blocks,block_no,piece_no+1);
buff_save_sprite(blocks,block_no,offscreen);
buff_draw_sprite(blocks,block_no,offscreen);
}
}
}
}
/***************************************************************************\
|* *|
|* The function place_piece takes the same parameters as draw_piece, *|
|* except for the flag, and does not draw the piece, but places it *|
|* on the board. No checking is done to see if it will fit, since *|
|* should already have been done by can_place(). *|
|* *|
\***************************************************************************/
void place_piece (piece_no, orient, y, x)
int piece_no;
int orient;
int y;
int x;
{
int i;
for (i = 0; i < NO_SQUARES; i++)
board[y+4+pieces[piece_no].index[orient][i][0]]
[x+pieces[piece_no].index[orient][i][1]] = piece_no;
}
/***************************************************************************\
|* *|
|* The function can_place takes the same parameters as place_piece, *|
|* It does not draw the piece, nor place it on the board, but returns *|
|* an integer value -- 0 if the piece will not fit on the board, 1 if *|
|* it will (with the specified orientation, position, etc.) *|
|* *|
\***************************************************************************/
#define HERE(x) pieces[piece_no].index[orient][i][x]
int can_place (piece_no, orient, y, x)
int piece_no;
int orient;
int y;
int x;
{
int i;
for (i = 0; i < NO_SQUARES; i++)
if (((x+HERE(1) >= GAME_WIDTH) || /* Off right of screen or */
(x+HERE(1) < 0)) || /* Off left of screen */
(y+HERE(0) >= GAME_DEPTH) || /* Off bottom of screen */
(board[y+4+HERE(0)][x+HERE(1)] != PI_EMPTY))
/* Board position not empty */
return (0);
return (1);
}
/***************************************************************************\
|* *|
|* flush_keyboard cleans the contents of the buffer. *|
|* *|
\***************************************************************************/
void flush_keyboard ()
{
kb_clear();
}
/***************************************************************************\
|* *|
|* get_keyboard_key checks the keyboard's buffer and returns the next *|
|* waiting key. Else, it waits until a key is hit. *|
|* *|
\***************************************************************************/
char get_keyboard_key() {
return kb_get_next_key();
}
/***************************************************************************\
|* *|
|* scan_key returns not zero if the key 'which' (scancode) is *|
|* being hit. *|
|* *|
\***************************************************************************/
char scan_key(int which) {
return kb_keydown(which);
}
/*-------------------------------------------------------------------------*/